namespace SimpleWebServices.Models
{
    using System.Xml.XPath;
    using SimpleWebServices;
    using SimpleWebServices.Data;
    using SimpleWebServices.Security.Cryptography;
    using Xunit;

    public sealed class InternationalAddressFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<InternationalAddress>()
                .DerivesFrom<SimpleWebServices.Data.Record>()
                .IsConcreteClass()
                .IsUnsealed()
                .HasDefaultConstructor()
                .XmlRoot("address")
                .Result);
        }

        [Fact]
        public void deserialize()
        {
            InternationalAddress actual = (
                "<address code='ABC123' key='test'>" +
                    "<coordinates longitude='-2.105470' latitude='53.493192' />" +
                    "<country urn='urn://geography/country/united-states-of-america' />" +
                    "<lines>" +
                        "<value name='city'>New York</value>" +
                    "</lines>" +
                "</address>").Deserialize<InternationalAddress>();

            Assert.NotNull(actual);

            Assert.Equal<string>("ABC123", actual.Code);
            Assert.Equal<decimal>(53.493192m, actual.Coordinates.Latitude);
            Assert.Equal<decimal>(-2.105470m, actual.Coordinates.Longitude);
            Assert.Equal<string>("urn://geography/country/united-states-of-america", actual.Country.Urn);
            Assert.Equal<string>("test", actual.Key);
            Assert.Equal<string>("New York", actual.Lines["city"]);
        }

        [Fact]
        public void deserializeEmpty()
        {
            InternationalAddress actual = "<address />".Deserialize<InternationalAddress>();

            Assert.NotNull(actual);

            Assert.Null(actual.Code);
            Assert.Null(actual.Coordinates);
            Assert.Null(actual.Country);
            Assert.Null(actual.Key);
            Assert.NotNull(actual.Lines);
        }

        [Fact]
        public void serialize()
        {
            InternationalAddress obj = new InternationalAddress
            {
                Code = "ABC123",
                Coordinates = new Coordinates
                {
                    Latitude = 53.493192m,
                    Longitude = -2.105470m
                },
                Country = new Country
                {
                    Urn = "urn://geography/country/united-states-of-america"
                },
                Key = "test",
                Lines = new DataCollection
                {
                    { "city", "New York" }
                }
            };

            XPathNavigator navigator = obj.Serialize().CreateNavigator();

            Assert.True((bool)navigator.Evaluate("1=count(/address[@key='test'][@code='ABC123']/coordinates[@longitude='-2.105470'][@latitude='53.493192'])"));
            Assert.True((bool)navigator.Evaluate("1=count(/address[@key='test'][@code='ABC123']/country[@urn='urn://geography/country/united-states-of-america'])"));
            Assert.True((bool)navigator.Evaluate("1=count(/address[@key='test'][@code='ABC123']/lines/value[@name='city'][text()='New York'])"));
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new InternationalAddress());
        }

        [Fact]
        public void prop_Code()
        {
            Assert.True(new PropertyExpectations(typeof(InternationalAddress).GetProperty("Code"))
                .XmlAttribute("code")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Coordinates()
        {
            Assert.True(new PropertyExpectations(typeof(InternationalAddress).GetProperty("Coordinates"))
                .XmlElement("coordinates")
                .IsAutoProperty<Coordinates>()
                .Result);
        }

        [Fact]
        public void prop_Country()
        {
            Assert.True(new PropertyExpectations(typeof(InternationalAddress).GetProperty("Country"))
                .XmlElement("country")
                .IsAutoProperty<Link<Country>>()
                .Result);
        }

        [Fact]
        public void prop_Entity()
        {
            Assert.True(new PropertyExpectations(typeof(InternationalAddress).GetProperty("Entity"))
                .XmlIgnore()
                .TypeIs<string>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_Entity_get()
        {
            InternationalAddress obj = new InternationalAddress
            {
                Code = "ABC123",
                Coordinates = new Coordinates
                {
                    Latitude = 53.493192m,
                    Longitude = -2.105470m
                },
                Country = new Country
                {
                    Urn = "urn://geography/country/united-states-of-america"
                },
                Lines = new DataCollection
                {
                    { "city", "New York" }
                }
            };

            string expected = "Kh2g8AwGVq/MZh9FiLRhnA==";
            string actual = MD5Hash.Compute(obj.Entity);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Entity_getEmpty()
        {
            string expected = string.Empty;
            string actual = new InternationalAddress().Entity;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Key()
        {
            Assert.True(new PropertyExpectations(typeof(InternationalAddress).GetProperty("Key"))
                .XmlAttribute("key")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Lines()
        {
            Assert.True(new PropertyExpectations(typeof(InternationalAddress).GetProperty("Lines"))
                .XmlElement("lines")
                .TypeIs<DataCollection>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void op_ToOfT()
        {
            InternationalAddress expected = new InternationalAddress
            {
                Code = "ABC123"
            };
            TestInternationalAddress actual = expected.To<TestInternationalAddress>();

            Assert.Equal<string>(expected.Code, actual.Code);
        }
    }
}